﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AForge.Video.DirectShow;
using AForge.Video;
using System.Threading;
using AForge.Controls;
using System.Drawing.Imaging;

namespace video_ai_2
{
    public partial class Form1 : Form
    {
        // opened video source
        private IVideoSource videoSource = null;
        // current statistics index
        private int statIndex = 0;
        // ready statistics values
        private int statReady = 0;

        bool LOCK = false;

        int frame = 0;
        byte k = 10;
        int filterID = 0;
        int[,] massive;
        int width = 0;
        int height = 0;
        string widthString = "";


        FilterInfoCollection videoDevices;
        private string device;

        private Thread demoThread = null;

        // Video device
        public string VideoDevice
        {
            get { return device; }
        }
        Bitmap imageGlobal;
        public Form1()
        {
            InitializeComponent();

            // show device list
            try
            {
                // enumerate video devices
                videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

                if (videoDevices.Count == 0)
                    throw new ApplicationException();

                // add all devices to combo
                foreach (FilterInfo device in videoDevices)
                {
                    comboBoxDevice.Items.Add(device.Name);
                }
                buttonCapture.Enabled = true;
            }
            catch (ApplicationException)
            {
                comboBoxDevice.Items.Add("Нет записывающих устройств.");
                buttonCapture.Enabled = false;
            }
            comboBoxDevice.SelectedIndex = 0;         
        }

        /// <summary>
        /// Открытие видео потока в плеере.
        /// </summary>
        /// <param name="source">Видео поток.</param>
        private void OpenVideoSource(IVideoSource source)
        {
            // set busy cursor
            this.Cursor = Cursors.WaitCursor;

            // close previous video source
            CloseVideoSource();
            // start new video source
            Player.VideoSource = source;
            Player.Start();

            // reset statistics
            statIndex = statReady = 0;
            videoSource = source;
            
            this.Cursor = Cursors.Default;
        }

        /// <summary>
        /// Закрытие видео потока.
        /// </summary>
        private void CloseVideoSource()
        {
            if (!(videoSource == null))
                if (videoSource.IsRunning)
                {
                    videoSource.SignalToStop();
                    videoSource = null;
                }
        }

        /// <summary>
        /// Закрытие видео потока при закрытие формы.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            CloseVideoSource();
        }

        private void buttonCapture_Click(object sender, EventArgs e)
        {
            if (buttonCapture.Text == "Начать захват")
            {
                device = videoDevices[comboBoxDevice.SelectedIndex].MonikerString;
                if (device != null)
                {

                    // create video source
                    VideoCaptureDevice videoSource = new VideoCaptureDevice(VideoDevice);
                    videoSource.DesiredFrameSize = new System.Drawing.Size(64, 48);
                    videoSource.DesiredFrameRate = 30;
                    //massive = new int[videoSource.DesiredFrameSize.Width, videoSource.DesiredFrameSize.Height]; 
                    width =  videoSource.DesiredFrameSize.Width;
                    height = videoSource.DesiredFrameSize.Height;

                    // open it
                    OpenVideoSource(videoSource);
                    //pictureBox1.Width = Player.Width;
                    //pictureBox1.Height = Player.Height;
                    buttonCapture.Text = "Остановить захват";
                    timerFPS.Start();
                }                
                else
                {
                    systemMessage.Text = "Ошибка: Не выбранно устройство.";
                }
            }
            else
            {
                if (videoSource.IsRunning)
                {
                    timerFPS.Stop();
                    frame = 0;
                    CloseVideoSource();
                    systemMessage.Text = "Захват окончен.";
                    buttonCapture.Text = "Начать захват";
                }
            }
        }

        private void videoSourcePlayer_NewFrame(object sender, ref Bitmap image)
        {       
            try
            {
                this.Invoke(new Action(() => { filterID = listBox1.SelectedIndex; }));
            }
            catch { }

            if (!LOCK && image.Width!=0)
            {
                LOCK = true;
                switch (filterID)
                {
                    case 1:
                        {
                            pictureBox1.Image = BW((Bitmap)image.Clone(), "bw");
                            break;
                        }
                    case 2:
                        {
                            pictureBox1.Image = BW((Bitmap)image.Clone(), "bwMY");
                            break;
                        }
                    case 3:
                        {
                            pictureBox1.Image = BW((Bitmap)image.Clone(), "filter 1");
                            break;
                        }
                    case 4:
                        {
                            pictureBox1.Image = BW((Bitmap)image.Clone(), "filter 2");
                            break;
                        }
                    case 5:
                        {
                            pictureBox1.Image = BW((Bitmap)image.Clone(), "BWfull");
                            break;
                        }
                    case 6:
                        {
                            matrix((Bitmap)image.Clone());
                            break;
                        }
                    default:
                        {
                            pictureBox1.Image = BW((Bitmap)image.Clone(), "");
                            break;
                        }
                }
                frame++;
            }            
        }

        unsafe void matrix(Bitmap inImage)
        {
            // Только 24 битные изображения
            if (inImage.PixelFormat != PixelFormat.Format24bppRgb)
                throw new ArgumentException();
            var bd = inImage.LockBits(
                new Rectangle(0, 0, inImage.Width, inImage.Height),
                ImageLockMode.ReadWrite,
                inImage.PixelFormat
            );
            var pStart = (byte*)bd.Scan0;
            var pEnd = (byte*)(pStart + bd.Stride * bd.Height);

            int w = 0, h = 0;

            while (pStart != pEnd)
            {
                byte avg = (byte)((*pStart + *(pStart + 1) + *(pStart + 2)) / 3);
                avg = (avg > 128) ? (byte)255 : (byte)0;
                char addMatrix = (avg > 0) ? '-' : '#';
                if (avg > 128 && avg < (255 - k)) avg += k;
                *pStart = *(pStart + 1) = *(pStart + 2) = avg;
                if (w < width - 1)
                {
                    widthString += addMatrix + ' ';
                    w++;
                }
                else
                {
                    try
                    {
                        this.Invoke(new Action(() => { if (listboxMatrix.Items.Count < height) listboxMatrix.Items.Add(widthString); else listboxMatrix.Items[h] = widthString; }));
                    }
                    catch { }
                    w = 0;
                    h++;
                    widthString = null;
                }
                pStart += 3;
            }
            inImage.UnlockBits(bd);

            LOCK = false;
            h = 0;
        }

        unsafe Bitmap BW(Bitmap inImage, string filter)
        {
            // Только 24 битные изображения
            if (inImage.PixelFormat != PixelFormat.Format24bppRgb)
                throw new ArgumentException();
            var bd = inImage.LockBits(
                new Rectangle(0, 0, inImage.Width, inImage.Height),
                ImageLockMode.ReadWrite,
                inImage.PixelFormat
            );
            var pStart = (byte*)bd.Scan0;
            var pEnd = (byte*)(pStart + bd.Stride * bd.Height);

            try
            {
                this.Invoke(new Action(() => { k = (byte)trackBar1.Value; }));
            }
            catch { }

            int w = 0, h = 0;
           
            /*
            try
            {
                this.Invoke(new Action(() => { listboxMatrix.Items.Clear(); listboxMatrix.Visible = false; }));
            }
            catch { }
            */

            while (pStart != pEnd)
            {
                switch (filter)
                {
                    case "bw":
                        {
                            // BGR
                            *pStart = *(pStart + 1) = *(pStart + 2) = (byte)(0.3 * *pStart + 0.59 * *(pStart + 1) + 0.11 * *(pStart + 2));
                            break;
                        }
                    case "bwMY":
                        {
                            // BW
                            byte avg = (byte)((*pStart + *(pStart + 1) + *(pStart + 2))/3);
                            if (avg <= 128 && avg > k) avg -= k;
                            if (avg > 128 && avg < (255 - k)) avg += k;
                            *pStart = *(pStart + 1) = *(pStart + 2) = avg;
                            break;
                        }
                    case "filter 1":
                        {
                            int r = (*pStart < 128) ? 0 : 255;
                            int g = (*(pStart + 1) < 128) ? 0 : 255;
                            int b = (*(pStart + 2) < 128) ? 0 : 255;                            
                            *pStart = (byte)r;
                            *(pStart + 1) = (byte)g;
                            *(pStart + 2) = (byte)b;
                            break;
                        }
                    case "filter 2":
                        {
                            int max = 0;
                            int r = *pStart;
                            int g = *(pStart + 1);
                            int b = *(pStart + 2);
                            max = (r > g) ? r : g;
                            max = (max > b) ? max : b;
                            if (max == r)
                            {
                                *pStart = (byte)r;
                                *(pStart + 1) = (byte)0;
                                *(pStart + 2) = (byte)0;
                            }
                            if (max == g)
                            {
                                *pStart = (byte)0;
                                *(pStart + 1) = (byte)g;
                                *(pStart + 2) = (byte)0;
                            }
                            if (max == b)
                            {
                                *pStart = (byte)0;
                                *(pStart + 1) = (byte)0;
                                *(pStart + 2) = (byte)b;
                            }
                            break;
                        }
                    case "BWfull":
                        {
                            // BW
                            byte avg = (byte)((*pStart + *(pStart + 1) + *(pStart + 2)) / 3);
                            avg = (avg > 128) ? (byte)255 : (byte)0;
                            char addMatrix = (avg > 0) ? '-' : '#';
                            if (avg > 128 && avg < (255 - k)) avg += k;
                            *pStart = *(pStart + 1) = *(pStart + 2) = avg;
                            if (w < width - 1)
                            {
                                widthString += addMatrix + ' ';
                                w++;
                            }
                            else
                            {
                                try
                                {
                                    this.Invoke(new Action(() => { if (listboxMatrix.Items.Count < height) listboxMatrix.Items.Add(widthString); else listboxMatrix.Items[h] = widthString; }));
                                }
                                catch { }
                                w = 0;
                                h++;
                                widthString = null;
                            } 
                            break;
                        }
                    default:
                        {
                            break;
                        }
                }
                pStart += 3;
            }
            inImage.UnlockBits(bd);

            LOCK = false;
            /*
            try
            {
                this.Invoke(new Action(() => { listboxMatrix.Visible = true; }));
            }
            catch { }
            */
            h = 0;
            return (Bitmap)inImage.Clone();
        }

        private void timerFPS_Tick_1(object sender, EventArgs e)
        {
            fps.Text = frame.ToString();
            try
            {
                progressBar2.Value = frame;
            }
            catch { }
            frame = 0;
        }
    }
}
